Skip to content

spec : add DFlash2 support (local convolution + candidate selector) - #27342

Merged
ngxson merged 16 commits into
ggml-org:xsn/dflash2from
z-lab:dflash2
Aug 27, 2026
Merged

spec : add DFlash2 support (local convolution + candidate selector)#27342
ngxson merged 16 commits into
ggml-org:xsn/dflash2from
z-lab:dflash2

Conversation

@SubSir

@SubSir SubSir commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Important

GGUF generated before Aug 27th 2026 must be reconverted, otherwise vision will be broken. See: #27342 (comment)

Overview

DFlash2 adds two more modules compared to DFlash, grouped dynamic depthwise convolution and candidate selector.

The formula is for reference. out[i,c] = Σ_t (base[t,c] + δ[i,t,g(c)]) · x[i−t,c]. base is the static kernel, δ is the dynamic part predicted from the input.x is divided into groups g(c) and δ is shared across a group. Another one is edge(p→c) = ⟨A[p] ⊙ project(h), B[c]⟩ + unary[c]. A/B are the codebooks for the predecessor and the candidate. This position's hidden is projected by project(h)to the same rank to multiply A. And unary[c] is the draft's own score for c.

DFlash2 is enabled when the checkpoint is DFlash2; no need to use extra flag.

We evaled Qwen3.8-27B at Q4_K_Mon Apple M5 Pro 64 GB. And the test data is first 8 problems of GSM8K.
Concurrency is set to 1 and temperature is 1.0, top-p 0.95, top-k 20. We use default xhigh reasoning and set
2,048 maximum new tokens.

Method Draft quant Block Decode TPS Decode speedup Acceptance Normal stops
Autoregressive 10.42 1.00× 8/8
DFlash2 BF16 8 19.31 1.85× 4.92 8/8
DFlash2 Q8_0 8 18.43 1.77× 5.08 8/8
DFlash2 Q4_K_M 8 18.89 1.81× 5.03 8/8

Requirements

  • I have read and agree with the contributing guidelines
  • AI usage disclosure: YES. Using AI to inspect and analyze code in the llama.cpp project, and using AI to update the code.

@SubSir
SubSir requested review from a team, CISC and ggerganov as code owners August 18, 2026 20:53
@ggml-gh-bot

ggml-gh-bot Bot commented Aug 18, 2026

Copy link
Copy Markdown

Hi @SubSir, thanks for your contribution!

Per our contribution guidelines, the automated PR checker found the following issue(s) that need your attention:

  • AI-generated content: While code is allowed to be generated by AI, please write the PR description and commit messages on your own without the help of AI.

Please note that maintainers reserve the right to make final decisions on PRs. If you believe there is a mistake, please comment below.

@SubSir

SubSir commented Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

I've revised the PR description. It's fully hand-written now.

@showgood163

This comment has been minimized.

@ManTouMT

This comment has been minimized.

Nathanw1014 added a commit to Nathanw1014/strix-halo-llamacpp that referenced this pull request Aug 19, 2026
…and DFlash v1

Adds docs/dflash2-strix.md with the four-arm llama-benchy comparison on
Qwen3.8-27B UD-Q4_K_XL, and vendors the unedited tool output under
benchmarks/results/dflash2-20260819/.

Headline, decode t/s at depth 0 / 8k / 32k:

  base (no spec decode)   11.81  11.44  10.54
  DFlash v1 (n=5)         21.09  12.87  10.75
  DFlash2 (n=4)           26.39  21.58  21.11
  DFlash2 (n=7)           25.18  21.46  16.32

DFlash2 holds about 2x over base at every depth measured, while DFlash v1
decays to 1.02x by 32k, i.e. by then it is worth nothing over plain decode.
Draft width matters at depth: at 32k, width 4 beats width 7 by 29 percent,
and the two tie at shallow depth.

DFlash2 engine support is upstream ggml-org/llama.cpp#27342 by Jian Chen and
is not our work; the page says so. What is ours is the gfx1151/Vulkan
validation and the draft-width tuning. Drafter weights are inco's published
Apache-2.0 GGUFs.

Measured with llama-benchy 0.4.0, which draws prompts from a Gutenberg book so
acceptance reflects real prose. Content matters more than expected here: a
code-corpus prompt set decays about 47 percent from shallow to 32k where this
corpus decays about 20 percent, so the page carries that caveat rather than
presenting one number as definitive. --runs 2, so the spec arms carry +/- 1.0
to 2.5 and only the 32k width gap is comfortably outside the noise.

Prefill was taken at the server default -ub 512; -ub 256 is the measured dense
optimum on these weights, so that column is a few percent below the ceiling.
Noted in the page, rerun deferred.

Assisted-by: Claude Opus 5
@am17an
am17an requested a review from ruixiang63 August 19, 2026 06:23
@KaruroChori

This comment has been minimized.

@Shamish

This comment was marked as off-topic.

@treo

treo commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

@Shamish There is already a fix for the reported problem at z-lab#1

As for the Performance on a single RTX3090, it seems to be not significantly better than MTP:

MTP:

$ ./build/bin/llama-server -m ~/.cache/huggingface/hub/models--unsloth--Qwen3.8-27B-GGUF/snapshots/f1bfb127c64f7072bdd2cad55f258b9c8b2910fe/Qwen3.8-27B-UD-Q4_K_XL.gguf  --fit off -np 1  -fa on --spec-type draft-mtp --spec-draft-n-max 3 --reasoning-preserve -c 32000 -ctk q8_0 -ctv q8_0

$ python speed_bench.py --url localhost:8080 --model qwen3.8-27b --concurrency 1 --limit 2
Warning: You are sending unauthenticated requests to the HF Hub. Please set a HF_TOKEN to enable higher rate limits and faster downloads.
speed_bench: loaded 22 samples from bench=qualitative category=all
speed_bench: 100%|██████████████████████████████████████████████████████████████████████████████████████████| 22/22 [11:57<00:00, 32.60s/sample]

Summary (elapsed=717.20s)
category       samples  avg_prompt_t/s  avg_pred_t/s  avg_latency  accept_rate
-------------  -------  --------------  ------------  -----------  -----------
coding         2        454.24          59.84         69.160s      0.6047     
humanities     2        508.66          57.24         56.283s      0.6075     
math           2        27.86           55.76         17.593s      0.5927     
qa             2        85.46           54.37         18.066s      0.5589     
rag            2        704.60          59.45         40.403s      0.6777     
reasoning      2        60.51           54.47         18.138s      0.5954     
stem           2        28.90           54.39         17.867s      0.5981     
writing        2        612.05          61.74         42.117s      0.6609     
multilingual   2        164.13          65.08         4.339s       0.7778     
summarization  2        131.48          54.36         4.965s       0.5473     
roleplay       2        397.24          58.95         69.665s      0.6814     
overall        22       288.65          57.79         32.600s      0.6317  

DFlash2 (using maxn=4 because 7 was slower):

$ ./build/bin/llama-server -m ~/.cache/huggingface/hub/models--unsloth--Qwen3.8-27B-GGUF/snapshots/f1bfb127c64f7072bdd2cad55f258b9c8b2910fe/Qwen3.8-27B-UD-Q4_K_XL.gguf  --fit off -np 1  -fa on --spec-type draft-dflash --spec-draft-n-max 4 --reasoning-preserve -c 32000 -ctk q8_0 -ctv q8_0 -md ~/.cache/huggingface/hub/models--incoai--Qwen3.8-27B-DFlash2-GGUF/snapshots/6cb5872e2cee6b4e780a8414922350be8e42d65c/Qwen3.8-27B-DFlash2-Q4_K_M.gguf

$ python speed_bench.py --url localhost:8080 --model qwen3.8-27b --concurrency 1 --limit 2
Warning: You are sending unauthenticated requests to the HF Hub. Please set a HF_TOKEN to enable higher rate limits and faster downloads.
speed_bench: loaded 22 samples from bench=qualitative category=all
speed_bench: 100%|██████████████████████████████████████████████████████████████████████████████████████████| 22/22 [11:40<00:00, 31.85s/sample]

Summary (elapsed=700.65s)
category       samples  avg_prompt_t/s  avg_pred_t/s  avg_latency  accept_rate
-------------  -------  --------------  ------------  -----------  -----------
coding         2        271.99          68.00         48.928s      0.6691     
humanities     2        470.70          59.87         62.873s      0.5610     
math           2        28.45           60.14         29.131s      0.5827     
qa             2        82.64           53.74         13.088s      0.5039     
rag            2        701.27          66.42         37.589s      0.6378     
reasoning      2        58.79           60.55         29.046s      0.5827     
stem           2        29.38           60.20         28.899s      0.5827     
writing        2        607.63          69.16         38.621s      0.6552     
multilingual   2        167.16          62.26         5.469s       0.5316     
summarization  2        136.16          59.60         4.324s       0.5690     
roleplay       2        375.62          64.43         52.359s      0.6758     
overall        22       266.35          62.21         31.848s      0.6153  

@Stoney49th

This comment has been minimized.

@ruixiang63 ruixiang63 self-assigned this Aug 19, 2026
@ruixiang63

Copy link
Copy Markdown
Member

Thanks for the PR. It would be great if you could run the benchmark on SpeedBench using the corresponding checkpoints and report the performance numbers. @SubSir

@KaruroChori

This comment has been minimized.

@Zeldatales

This comment has been minimized.

@jhstatewide

This comment has been minimized.

@cobra91

cobra91 commented Aug 27, 2026

Copy link
Copy Markdown

CUDA graphs ruled out too — on the slow build (2474373), GGML_CUDA_DISABLE_GRAPHS set → 135 tok/s vs 163 with graphs on (3-run avgs). Graphs are present, working, and helping; the regression isn't graph capture/reuse.

So the elimination list is now: top-k kernel ❌, draft sampling ❌, p_min ❌, CUDA graphs ❌ — and notably the regression is NVFP4-specific on my side too (DFlash2 decode on a Qwen3.8-27B IQ3 target is unchanged between the two heads). That pattern is consistent with your second hypothesis: the NVFP4 post-scale fusion path. Whatever it is, it lands in the first 4 commits (1deefcc..2474373).

@ORippler

ORippler commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator
image

I took nsys to qwen3.8 + dflash2 on the B4500. Per amdahl's law, we would expect up to ~1.3% E2E speed-up if me make top-k instantaneous (6 / 450 ms). While we are 2x faster at the kernel-level, this translates to an expected perf gain of 0.5% (which drowns in the other noise).

What we should be looking at instead to accelerate DFLASH2 in llama.cpp (viewed through the eyes of a CUDA engineer):

  1. Enable more reusable graphs (no/too little cudaGraph's used)
  2. Better memory management and movement (get rid of everything red/orange in the nsys graph).
    • Enable D2D copies over the D2H2D trips
    • See if we can allocate a re-usable host pool over doing repeated cudaFree/cudaMallocHost cycles
    • Less syncs when moving inputs
  3. There are large idle spots in the GPU timeline, have not fully dug into what actually happens there -> Potentially offload the greedy walk to a backend?

Best

@cobra91

cobra91 commented Aug 27, 2026

Copy link
Copy Markdown

Completing the retraction with the head commit — greedy bench (temp=0, warmup discarded, 6 runs): 2f3923b = 186/188/185/189/189/186, avg 187 — identical to the 5ecbe1a baseline (188 avg). Full greedy picture:

Build Greedy decode avg Acceptance
5ecbe1a (pre-window) 188 71%
1deefcc (commit 1) 185 70%
2f3923b (head) 187 70%

No regression anywhere in the window — the PR is performance-clean from my side. (Also noted: first-generation-after-load runs ~10% slow — always warm up before measuring.)

anthony-chaudhary added a commit to anthony-chaudhary/fak that referenced this pull request Aug 27, 2026
Evaluate the algorithmic DFlash2 selector boundary without importing an untrained convolution layer.

Prior-art: ggml-org/llama.cpp#27210; ggml-org/llama.cpp#27342
Signed-off-by: Codex <codex@openai.com>
(fak model)
@Eric-A-Stalee

Eric-A-Stalee commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

FYI for anyone benchmarking this on Vulkan

DFlash 2 verify graph triggers a pre-existing bug #27805 in ggml_vk_graph_optimize (ggml-vulkan.cpp, not touched by this PR).

The optimizer does not see dependencies between different views of one tensor and can reorder across them, so on Vulkan the main model accepts draft tokens it did not choose: wrong output at temperature 0. CUDA is not affected. Fix in #27812. Until a fix is implemented upstream, Vulkan acceptance and speed numbers for this PR are invalid. GGML_VK_DISABLE_GRAPH_OPTIMIZE=1 is not a benchmarking workaround either as it does not fix the underlying performance code; it only fixes correctness, potentially at the cost of performance.

quickstraw added a commit to quickstraw/llama.cpp that referenced this pull request Aug 27, 2026
@ngxson

ngxson commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

I'm merging this PR now as it's already a good baseline. For bug reports, please fire separate issues

@ngxson

This comment was marked as outdated.

@ngxson

ngxson commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Nevermind my last comment. Let's remove the CUDA change as @ORippler requested. I'm pushing a commit to remove it and will merge this PR once the CI passes

@SubSir please feel free to move the CUDA top-k change to a new PR, that will be better for discussions

@ngxson

ngxson commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

hmm bad news then, this PR is created from an org, I cannot push to it

image

@ngxson
ngxson changed the base branch from master to xsn/dflash2 August 27, 2026 17:05
@ngxson
ngxson merged commit 4a6ad48 into ggml-org:xsn/dflash2 Aug 27, 2026
27 of 32 checks passed
@ORippler

Copy link
Copy Markdown
Collaborator

@SubSir please feel free to move the CUDA top-k change to a new PR, that will be better for discussions

+1, there are also other efforts ongoing to enable top-k for AMD in the CUDA backend #27466

ngxson added a commit that referenced this pull request Aug 27, 2026
…27342) (#27816)

* spec : add DFlash2 support (local convolution + candidate selector) (#27342)

* support DFlash2

* Add p_min in DFlash2

Assisted-by: Claude Opus 5

* Revert unnecessary changes

Assisted-by: Claude Opus 5

* Revert draft sampling in rejection sampling

Assisted-by: Claude Opus 5

* Refactor code structure

Assisted-by: Claude Opus 5

* Delete embedding scaling

Assisted-by: Claude Opus 5

* Gate output transforms on DFlash2

Assisted-by: Claude Opus 5

* Optimize Dflash 2 cost

Assisted-by: Claude Opus 5

* Avoid using atoi

Assisted-by: Claude Opus 5

* Modify comments

Assisted-by: Claude Opus 5

* Move llama_model_dflash_selector_top_k to llama-ext.h

Assisted-by: Claude Opus 5

* Formatting

Assisted-by: Claude Opus 5

* Apply patch to fix the mrope bug

Assisted-by: Claude Opus 5

* fix ci

Assisted-by: Claude Opus 5

* Fix graph number calculation

Assisted-by: Claude Opus 5

* rename hid and unary

Assisted-by: Claude Opus 5

---------

Co-authored-by: Jian Chen <jianchen0311@gmail.com>
Co-authored-by: Xuan-Son Nguyen <son@huggingface.co>

* revert top-k.cu changes

---------

Co-authored-by: Zihan Zhang <tiancaizhangdaxian@sjtu.edu.cn>
Co-authored-by: Jian Chen <jianchen0311@gmail.com>
Patt92 pushed a commit to Patt92/llama.cpp that referenced this pull request Aug 27, 2026
Upstream merged PR ggml-org#27342 as b10f9ca, so the fork's own port of that PR
is now a duplicate. Per the refresh rule, take the upstream implementation
and drop the fork hunks: greedy selection with a p_min threshold replaces
the fork's stochastic maximal-coupling sampling, and the encoder path gains
upstream's M-RoPE position handling. This removes selector_rng,
selector_reset and the dists-based DFlash2 sampling.

Keep Nathan's capability guard from 0b0f35d on top: a DSV4 backbone must
still be refused explicitly, because its graph does not build the selector
lattice. Align llama_model_dflash::graph with upstream, which no longer
overrides build_post_sampling.

conversion/qwen.py and gguf-py/gguf/constants.py take upstream verbatim:
an interleaved-rope permute the fork lacked, and pure alignment.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@MEsfits

MEsfits commented Aug 27, 2026

Copy link
Copy Markdown

does this fix dflash2 running on multi-gpu setups ? -sm tensor not working on previous iterations

@TheFuchsen

Copy link
Copy Markdown

does this fix dflash2 running on multi-gpu setups ? -sm tensor not working on previous iterations

Nope, still there:

C:\llama\llama.cpp\ggml\src\ggml-backend-meta.cpp:543: GGML_ASSERT(src_ss[0].axis != GGML_BACKEND_SPLIT_AXIS_0) failed

Anbeeld added a commit to Anbeeld/beellama.cpp that referenced this pull request Aug 27, 2026
Merge upstream PR ggml-org#27342 at 2f3923b into BeeLlama v0.4.4 at 1ce739a (common base 9731ad3).

The merge had no textual conflicts. The reviewed integration preserves BeeLlama speculative state restore, DSpark, reduced-vocabulary, KVarN, and KV-tail behavior while adding DFlash2 convolution, selector, M-RoPE, converter/GGUF plumbing, and wide-row CUDA top-k support. Use -FLT_MAX for empty CUDA top-k candidates to avoid a CUDA 13.1 overflow warning.

Verified with the Windows CPU build and 100/100 CPU tests; the CUDA 13.1 sm_86 default build script in shared and all-tests configurations; 100/100 CUDA tests; 80 targeted wide-row CUDA top-k cases and CUDA top-k perf runs; targeted checkpoint/state tests; real legacy DFlash conversion and speculative decoding; real DFlash2 conversion, GGUF metadata/tensor inspection, and model tensor validation.
vcruz305 pushed a commit to vcruz305/llama.cpp that referenced this pull request Aug 28, 2026
…gml-org#27342)

* support DFlash2

* Add p_min in DFlash2

Assisted-by: Claude Opus 5

* Revert unnecessary changes

Assisted-by: Claude Opus 5

* Revert draft sampling in rejection sampling

Assisted-by: Claude Opus 5

* Refactor code structure

Assisted-by: Claude Opus 5

* Delete embedding scaling

Assisted-by: Claude Opus 5

* Gate output transforms on DFlash2

Assisted-by: Claude Opus 5

* Optimize Dflash 2 cost

Assisted-by: Claude Opus 5

* Avoid using atoi

Assisted-by: Claude Opus 5

* Modify comments

Assisted-by: Claude Opus 5

* Move llama_model_dflash_selector_top_k to llama-ext.h

Assisted-by: Claude Opus 5

* Formatting

Assisted-by: Claude Opus 5

* Apply patch to fix the mrope bug

Assisted-by: Claude Opus 5

* fix ci

Assisted-by: Claude Opus 5

* Fix graph number calculation

Assisted-by: Claude Opus 5

* rename hid and unary

Assisted-by: Claude Opus 5

---------

Co-authored-by: Jian Chen <jianchen0311@gmail.com>
Co-authored-by: Xuan-Son Nguyen <son@huggingface.co>
@art-den

art-den commented Aug 28, 2026

Copy link
Copy Markdown

@MEsfits @TheFuchsen PR to fix -sm tensor: #27858

@ngxson

ngxson commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Important

GGUF generated before Aug 27th 2026 must be reconverted, otherwise vision will be broken. See: #27342 (comment)

Many broken GGUFs are still being distributed from incoai account, that is known to be broken.

Please, ask them to reconvert GGUF, or simply download from official z-lab account.

@ali-thowfeek

ali-thowfeek commented Aug 29, 2026

Copy link
Copy Markdown

Important

GGUF generated before Aug 27th 2026 must be reconverted, otherwise vision will be broken. See: #27342 (comment)

Many broken GGUFs are still being distributed from incoai account, that is known to be broken.

Please, ask them to reconvert GGUF, or simply download from official z-lab account.

@ngxson Are these the correct GGUFs: https://huggingface.co/z-lab/Qwen3.8-27B-DFlash2-GGUF?

Because using Q4KM of the above repos when i give it an image, the acceptance falls down severely to less than 0.03
But if i switch to MTP works as expected.

Update: incoai just upload the GGUFs, I'm seeing the same issue:
https://huggingface.co/incoai/Qwen3.8-27B-DFlash2-GGUF

LaurentZuijdwijk pushed a commit to LaurentZuijdwijk/llama.cpp that referenced this pull request Aug 31, 2026
Upstream's merged DFlash2 (b10f9ca, ggml-org#27342) builds the selector from the
decoder graph constructor via build_dflash2_selector, and has no
build_post_sampling hook at all. The hook and its call site came from the
PR-stage version cherry-picked earlier; the upstream merge removed the call
site, so the re-added override was never reached.

Removes the duplicate implementation and the now-unused virtual, which puts
llama-graph.h back at parity with upstream.

Assisted-by: Claude Opus 5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conversion CUDA Related to the CUDA backend ggml changes relating to the ggml tensor library for machine learning model Model specific server testing Everything test related

Projects

None yet

Development

Successfully merging this pull request may close these issues.